iT邦幫忙

2021 iThome 鐵人賽

DAY 9
0
Modern Web

關於我作夢變成工程師這檔事(Angular 篇)系列 第 9

第 9 天 元件還是頁面,這是個問題|page、component

  • 分享至 

  • xImage
  •  

前情提要

藉著重構原先從元件取得資料的方法,我們將對 http 的呼叫封裝在服務裡,隱藏了資料來源的細節。這使我們在元件中在可以更專注於與畫面的互動。並且,如果在兩個元件中都需要取得英雄列表,不必在兩處撰寫相同的程式碼,只需要注入服務使用方法便可取得。日後如資料來源有所異動,也僅需調整 service 中的方法。

當然,當我們從元件中呼叫服務中的方法取得資料後,在資料流到訂閱處之前,可以使用 RxJS 的管道(pipe)加上操作符(operators)來加工資料。因此在不同的元件需求下,可以使用服務的同一個方法,透過不同的加工讓來取得符合需求的資料。

接下來,我們將實作新增英雄功能。在此之前,我們先來思考一個問題:元件(component)還是頁面(page)?

什麼是頁面?

一個簡單的說明是:一個路由對應的就是一個頁面。

打開 app-routing.module.ts 查看目前的路由設定:

const routes: Routes = [
  {
    path: '',
    redirectTo: '/heroes',
    pathMatch: 'full'
  },
  {
    path: 'heroes',
    children: [
      {
        path: '',
        component: HeroListComponent
      },
      {
        path: ':id',
        component: HeroDetailComponent,
      }
    ]
  },
]

每個 path 會呈現的畫面就是頁面(page),現在可以看到主要使用了兩個元件 HeroListComponent 、 HeroDetailComponent 來呈現頁面。如果在這個情境下,思考「元件還是頁面」似乎有些匪夷所思。而且,這重要嗎?

我只能說細思極恐。的確,我們現在直接將兩個元件用作頁面,但請記得元件的特點是可複用性。在沒有特別的規範下,元件是可以在同一個 module 裏面被任意使用的;如果你將這個元件匯出(export),那有匯入(import)此 module 的地方都可以使用。

當我們在規劃頁面時,它往往具備特殊性,並非可以任意當作組件放入其他元件中。試想,如果剛加入一個已啟動一陣子的案子,或是接手維護一個專案,當你調整了某個畫面上使用的元件,會預期某個頁面會因為這個調整發生改變嗎——甚至是產生 bug。

在 Angular 裡,我們可以透過元件@Component裝飾器的元資料中不提供 selector,自然,其他地方就無法使用這個元件。使用 Angular CLI 的話,我們可以在新增元件的時候加入參數 --skip-selector 來自動完成這個改動:

ng g c add-hero --skip-selector // g for generate, c for component

這樣新增元件的 @Component 裝飾器內的元資料就不會有 selector:

import { Component, OnInit } from '@angular/core';

@Component({
  templateUrl: './add-hero.component.html',
  styleUrls: ['./add-hero.component.css']
})
export class AddHeroComponent implements OnInit {

  constructor() { }

  ngOnInit(): void {
  }

}

如果你安裝了保哥的 Angular Extension Pack,你可以這樣進行操作,一個指令都不用背:

https://ithelp.ithome.com.tw/upload/images/20210924/20128395u3p80kyUGT.png

  1. 從 sidebar 點擊 Angular 圖示打開命令清單。
  2. 在清單選擇 component。
  3. 輸入欲新增的 component 名稱。

輸入 component 並點擊 enter 後,就會出現是否添加參數的清單:

https://ithelp.ithome.com.tw/upload/images/20210924/20128395k0bSXNHq3H.png

選擇「Page --skip selector」就會自動新增一個頁面,也就是不提供 selector 的元件

那麼,元件還是頁面?

除了防止頁面層級的元件遭到誤用之外,我們還可以透過思考「元件還是頁面」,來不斷優化自己的專案設計。

以即將開始實作的「新增英雄」功能(AddHeroComponent)為例,我們來思考「元件還是頁面」?

可以想見,「新增英雄」功能的畫面上,我們會有一個輸入英雄資料的表單,當使用者填寫完成後就可以點擊按鈕將資料送出,完成英雄的新增。這個表單,我們應該將它製作成元件,例如 HeroDataFormComponent。你馬上可以想到,我們可能會提供另外一個「編輯英雄」功能,屆時,很大的機率會使用類似、甚至是相同的表單。

如果我們直接將 HeroDataFormComponent 配置路由,也就是將它作為頁面使用,那會有什麼問題?一個可能是,在「新增英雄」功能與「編輯英雄」功能的畫面其實不盡相同,新增英雄的部分也許會額外顯示同一種類型(刺客、坦克、鬥士...)的英雄作為參考,而編輯英雄並不需要顯示這些資訊。

在這種需求下,如果我們直接兩個功能的路由導向表單元件,那我們可能需要依據身處的路由,在表單元件裡動態生產許多不同的東西,例如引用其他元件。當需要判斷的情形越多,這個元件就會越難管理。想用使用這個元件的其他成員,要了解這個元件的邏輯成本也增加了。想想,當你使用一個包好的元件,而元件的 API 非常複雜的時候...。能夠達成目標是好事,但人生是不是可以更簡單一些呢?

在專案結構的設計上,你也可以特別在資料夾或是檔案名稱來區分它們。例如在每個功能模組中(feature module),建立pages 資料夾放置頁面元件。或是在新增不帶 selecor 的元件時,將其命名為 AddHeroPageComponent 諸如此類。

所以,在實作功能時,你會怎麼規劃它的頁面及元件呢?


上一篇
第 8 天 邁出 RxJS 小小的一步|pipe、operators
下一篇
第 10 天 別說呂布了,你聽過青銅五小強嗎 |Template-driven-form、ngModel、Template variables
系列文
關於我作夢變成工程師這檔事(Angular 篇)14
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言